<?php
/**
 * the view stack of elements
 * this contains:
 * raw elements
 * js/css/img tools
 * header
 * body
 * tags
 * meta
 * all possible HTML elements in one place.
 * @uses
 */
class Blib_View_Stack extends Blib_Data_Collection
{
    /**
     * initialise all stacks in the constructor
     * @return void
     */
    public function __construct($params = array())
    {
        parent::__construct($params);
        // init the internal stacks
        $this->addMulti(array(
            'HEAD' => array(),
            'BODY' => array(),
        ));
        // add default cont type to utf-8
        $this->contentType();

    } // end __construct

/*======================================[tag apis]======================================*/

    /**
     * head tags
     * set all to HEAD
     * @param str $group the group name
     * @param str $name the name
     * @param str $name the tag name
     * @param str $value can be null
     * @param array $attr the attributes, default is array
     * @return self
     */
    public function head($group, $name, $tagName, $value = null, $attr = array())
    {
        $tag = new Blib_View_Tag($tagName);
        $tag->attr($attr)
            ->value($value);
        $this->_data['HEAD'][$group][$name] = $tag;
        return $this;

    }// end head


    /**
     * get rid of head meta tags
     * @param str $group the group name: meta|title|desc|js|css etc
     * @param str $name the name
     * @return self
     */
    public function deHead($group, $name)
    {
        if (isset($this->_data['HEAD'][$group][$name])) {
            unset($this->_data['HEAD'][$group][$name]);
        }
        return $this;

    }// end deHead


    /**
     * get head meta tags
     * @param str $group the group name: meta|title|desc|js|css etc
     * @param str $name the name
     * @return mixed
     */
    public function getHead($group, $name, $tagName = null)
    {
        if (!isset($this->_data['HEAD'][$group][$name]) ||
            !$this->_data['HEAD'][$group][$name] instanceof Blib_View_Tag) {
            if (empty($tagName)) {
                $tagName = $name;
            }
            $this->_data['HEAD'][$group][$name] = new Blib_View_Tag($tagName);
        }
        return $this->_data['HEAD'][$group][$name];

    }// end deHead


    /**
     * get header out
     * @param bool $raw if true return raw, otherwise echo out
     * @return mixed
     */
    public function header($raw = true)
    {
        $header = null;
        foreach ($this->get('HEAD') as $group => $tags) {
            echo '<!-- ' . $group . ' -->' . "\n";
            foreach ((array) $tags as $tag) {
                echo $tag . "\n";
            }
        }

        if ($raw) {
            return $header;
        }

        echo $header;
        return $this;

    }// end header

/*======================================[meta]======================================*/

    /**
     * set http-equiv meta
     * @param str $key the key
     * @param str $val the value
     * @return self
     */
    public function httpMeta($key, $val)
    {
        return $this->head('meta', $key, 'meta', '', array('HTTP-EQUIV' => $key, 'CONTENT' => $val));

    } // end httpMeta

    /**
     * set name meta
     * @param str $key the key
     * @param str $val the value
     * @return self
     */
    public function nameMeta($key, $val)
    {
        return $this->head('meta', $key, 'meta', '', array('NAME' => $key, 'CONTENT' => $val));

    } // end nameMeta

    /**
     * remove meta tags
     * @param str $key the key
     * @return self
     */
    public function removeMeta($key)
    {
        return $this->deHead('meta', $key);

    }// end removeMeta

    /**
     * retrieve meta tags
     * @param str $key the key
     * @param str $tagName the tag name
     * @return mixed
     */
    public function getMeta($key)
    {
        return $this->getHead('meta', $key, 'meta');

    }// end getMeta


    /**
     * special one
     * @param str $type the content type
     * @return self
     */
    public function contentType($type = 'text/html; charset=UTF-8')
    {
        return $this->nameMeta('content-type', $type);

    } // end contentType


    /**
     * special one
     * @param str $value the keywords
     * @param str $type SET|APPEND|PREPEND
     * @return self
     */
    public function keywords($value, $type = 'SET')
    {
        // need to get existing keywords out first
        $this->getMeta('keywords')->attr('CONTENT', $value, $type, ', ');
        return $this;

    } // end keywords


    /**
     * special one
     * @param str $desc the description
     * @param str $type SET|APPEND|PREPEND
     * @return self
     */
    public function desc($value, $type = 'SET')
    {
        // need to get existing keywords out first
        $this->getMeta('description')->attr('CONTENT', $value, $type, ', ');
        return $this;

    } // end desc


    /**
     * special one
     * @param str $title the title
     * @param str $type SET|APPEND|PREPEND
     * @return self
     */
    public function title($title = null, $type = 'SET')
    {
        // get title out if null
        if (empty($title)) {
            return $this->getHead('tag', 'title')->value();
        }

        // fix
        $this->getHead('tag', 'title')->value($title, $type);
        return $this;

    } // end desc

/*======================================[js + css]======================================*/

    /**
     * add JS
     * @param str $src can be either linked or plain src
     * @param type $type can be SET|APPEND|PREPEND for raw src only
     * @return self
     */
    public function js($src, $type = 'APPEND')
    {
        // url should never contain ; - only js will have ; or multiple lines
        if (strpos($src, ';') !== false || strpos($src, "\n") !== false) {
            // it's raw js
            $this->getHead('JS', 'RAW', 'script')
                 ->value($src, $type, "\n")
                 ->attr('type', 'text/javascript');
            return $this;
        }

        // it's a link
        $this->getHead('JS', $src, 'script')
             ->attr('type', 'text/javascript')
             ->attr('src', $src)
             ->value(' ');
        return $this;

    }// end js


    /**
     * add css
     * @param str $src can be source (raw) or linked src
     * @param str $media default screen, can be print|projector|etc
     * @param type $type can be SET|APPEND|PREPEND for raw src only
     * @return self
     */
    public function css($src, $media = 'screen', $type = 'APPEND')
    {
        // url should never contain {}
        if (strpos($src, '}') !== false) {
            // it's raw css
            $this->getHead('CSS', 'RAW', 'style')
                 ->value($src, $type, "\n")
                 ->attr('type', 'text/css')
                 ->attr('media', $media);
            return $this;
        }

        // it's a link
        $this->getHead('CSS', $src, 'link')
             ->attr('type', 'text/css')
             ->attr('rel', 'stylesheet')
             ->attr('media', $media)
             ->attr('href', $src);
        return $this;

    }// end css

/*======================================[body]======================================*/

}// end Blib_View_Stack
?>